package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"gitee.com/relay/com"
	"github.com/valyala/fasthttp"
	"log"
	"strings"
	"time"
	"github.com/buaazp/fasthttprouter"
)

var addr = flag.String("addr", ":7380", "http service address")

var registerHandler fasthttp.RequestHandler
var pushHandler fasthttp.RequestHandler
var queryHandler fasthttp.RequestHandler
var getHandler fasthttp.RequestHandler
var macHandler  fasthttp.RequestHandler
var sdpHandler  fasthttp.RequestHandler




func main() {
	flag.Parse()
	nodes := &com.Nodes{
		Host: make(map[string]com.NodeHost),
	}
	nodes.Run()
	router := fasthttprouter.New()
	router.POST("/push", push)
	router.POST("/register", register)
	router.GET("/query", query)
	router.POST("/get", get)
	router.GET("/mac",mac)
	router.POST("/sdp",sdp)
	registerHandler = func(ctx *fasthttp.RequestCtx) {
		announce := com.NewHost()
		announce.Handle(nodes, ctx)
		//TODO test
		announce.Reset()
	}
	pushHandler = func(ctx *fasthttp.RequestCtx) {
		nodePush(nodes, ctx)
	}
	queryHandler = func(ctx *fasthttp.RequestCtx) {
		nodeQuery(nodes, ctx)
	}
	getHandler = func(ctx *fasthttp.RequestCtx) {
		nodeGet(nodes, ctx)
	}

	macHandler = func(ctx *fasthttp.RequestCtx) {
		macGet(nodes, ctx)
	}
	sdpHandler = func(ctx *fasthttp.RequestCtx) {
		sdpDelete(nodes, ctx)
	}

	err := fasthttp.ListenAndServe(*addr, router.Handler)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}




}





func register(ctx *fasthttp.RequestCtx) {
	registerHandler(ctx)
}

func push(ctx *fasthttp.RequestCtx) {
	pushHandler(ctx)
}
func query(ctx *fasthttp.RequestCtx) {
	queryHandler(ctx)
}
func get(ctx *fasthttp.RequestCtx) {
	getHandler(ctx)
}
func mac(ctx *fasthttp.RequestCtx) {
	macHandler(ctx)
}
func sdp(ctx *fasthttp.RequestCtx) {
	sdpHandler(ctx)
}

func nodePush(node *com.Nodes, ctx *fasthttp.RequestCtx) {

	to := string(ctx.QueryArgs().Peek("to"))
	from := string(ctx.QueryArgs().Peek("from"))
	peer := node.GetNodeHost(to)
	log.Printf("node push get node:%v; host:%v",to,peer)
	body := ctx.Request.Body()
	if peer != "" {
		go func() {
	//		log.Printf("push to register server")
	//		log.Printf("push to register server body: %v",string(body))
			const baseUrl = "push?to=%s&from=%s"
			fastClient := &fasthttp.Client{
			ReadTimeout: 5*time.Second,
			}
			req := fasthttp.AcquireRequest()
			req.Header.SetMethod("POST")
			req.SetRequestURI(fmt.Sprintf(baseUrl, strings.ToLower(to),strings.ToLower(from)))
			req.SetHost(peer)
			req.SetBody(body)
			resp := fasthttp.AcquireResponse()
			if err := fastClient.DoTimeout(req, resp, 10*time.Second); err != nil {
				log.Printf("node push to server:%s ",err)
			}
			//		TODO
		}()
		sdp,err := node.GetNodePull(to,1)
		if err != nil{
			log.Printf("[error] node push get node pull err:%v",err)
		}
		sdpResp,err := json.Marshal(sdp)
		if err != nil{
			log.Printf("[error] node push json marshal err:%v",err)

		}
		ctx.Response.SetBody(sdpResp)



	} else {
		type errPullRsponse struct {
			ErrorCode  int `json:"errorcode"`
			Msg  string `json:"msg"`
			Uuid  string `json:"uuid"`
			ToUuid  string `json:"to_uuid"`
		}
		body,err := json.Marshal(errPullRsponse{ErrorCode: 4004,Msg: "no such node",Uuid: from,ToUuid: to})
		if err != nil{
			log.Printf("node push find no node json marshal err:%v",err)
		}
		ctx.Response.SetBody(body)
	}
}

func nodeQuery(node *com.Nodes, ctx *fasthttp.RequestCtx) {
	var peer *com.PullRespsonse
	var toPeer *com.PullRespsonse
	uid := ctx.QueryArgs().Peek("uid")
	toUid := ctx.QueryArgs().Peek("toUid")
//	log.Printf("node query uid:%v",string(uid))
//	log.Printf("node query touid:%v",string(toUid))
	if toUid != nil {
		toPeer = node.GetPullNodeAnnounce(toUid)
		//log.Printf("node query topeer:%v",toPeer)
		if toPeer !=nil {
			toResp, err := json.Marshal(toPeer)
			if err != nil {
				log.Printf("[err]:node query json encode err::->%v", err)
			}
			log.Printf("node query in station toUid:%s got:%v",string(toUid),string(toResp))
			ctx.Response.Header.SetBytesV("toPeer", toResp)
		}
	} else {
		log.Printf("[waring]:when nodequery not find node:->%v", string(toUid))
	}
	if uid != nil {
		peer = node.GetPullNodeAnnounce(uid)
	//	log.Printf("node query peer:%v",peer)
		if peer != nil {
			resp, err := json.Marshal(peer)
			if err != nil {
				log.Printf("[waring]:when nodequery not find node:->%v", string(uid))
			}
	//		log.Printf("node query in station uid:%s got:%p",string(uid),resp)
			ctx.Response.Header.SetBytesV("peer", resp)
		}
	}
}
func nodeGet(node *com.Nodes, ctx *fasthttp.RequestCtx) {
	var macs com.Scheduler
	var peers []*com.NodeAnnounce
	log.Printf("[info]: node get request body:%v",string(ctx.Request.Body()))
	if len(ctx.Request.Body()) != 0 {
		err := json.Unmarshal(ctx.Request.Body(),&macs)
		if err != nil {
			log.Printf("[error]: node get json unmarshal err:%v",err)
		}

		for _,mac := range macs.Nodes{
			node:= node.GetNodeAnnounce(mac.Mac)
			if node != nil{
				log.Printf("[info]: node range:%v",node)
				peers = append(peers,node)
			}
		}
		log.Printf("[info]: station node get len:%d",len(peers))
		if len(peers) !=0 {
			resp, err := json.Marshal(peers)
			if err != nil {
				log.Printf("[error]: station node resp json marshal err:%v", err)
			}
			log.Printf("[info]: station node get:%d",len(resp))
			ctx.Response.SetBody(resp)
		}

	}

}

func macGet(node *com.Nodes, ctx *fasthttp.RequestCtx) {
	macResp := new(com.Mac)
	mac := string(ctx.Request.Header.Peek("mac"))
	macResp = node.GetNodeMac(mac)
	b,err := json.Marshal(macResp)
	if err != nil{
		ctx.Response.SetBody([]byte("internal error"))
	}
	ctx.Response.SetBody(b)

}

func sdpDelete(node *com.Nodes,ctx *fasthttp.RequestCtx)  {
		client := ctx.QueryArgs().Peek("client")
		if client != nil{
			node.DelNodeSdp(string(client))

		}


}
